#include "pch.h"
#include "Helpers.h"

using namespace Microsoft::Media::FragmentedMediaSink;

void Helpers::AddAttribute(_In_ GUID guidKey, _In_ IPropertyValue ^value, _In_ IMFAttributes *pAttr)
{
	PropertyType type = value->Type;
	switch (type)
	{
	case PropertyType::UInt8Array:
	{
		Array<BYTE>^ arr;
		value->GetUInt8Array(&arr);

		ThrowIfError(pAttr->SetBlob(guidKey, arr->Data, arr->Length));
	}
		break;

	case PropertyType::Double:
	{
		ThrowIfError(pAttr->SetDouble(guidKey, value->GetDouble()));
	}
		break;

	case PropertyType::Guid:
	{
		ThrowIfError(pAttr->SetGUID(guidKey, value->GetGuid()));
	}
		break;

	case PropertyType::String:
	{
		ThrowIfError(pAttr->SetString(guidKey, value->GetString()->Data()));
	}
		break;

	case PropertyType::UInt32:
	{
		ThrowIfError(pAttr->SetUINT32(guidKey, value->GetUInt32()));
	}
		break;

	case PropertyType::UInt64:
	{
		ThrowIfError(pAttr->SetUINT64(guidKey, value->GetUInt64()));
	}
		break;

		// ignore unknown values
	}
}

void Helpers::ConvertPropertiesToMediaType(_In_ IMediaEncodingProperties ^mep, _Outptr_ IMFMediaType **ppMT)
{
	if (mep == nullptr || ppMT == nullptr)
	{
		throw ref new InvalidArgumentException();
	}
	ComPtr<IMFMediaType> spMT;
	*ppMT = nullptr;
	ThrowIfError(MFCreateMediaType(&spMT));

	auto it = mep->Properties->First();

	while (it->HasCurrent)
	{
		auto currentValue = it->Current;
		AddAttribute(currentValue->Key, safe_cast<IPropertyValue^>(currentValue->Value), spMT.Get());
		it->MoveNext();
	}

	GUID guiMajorType = safe_cast<IPropertyValue^>(mep->Properties->Lookup(MF_MT_MAJOR_TYPE))->GetGuid();

	if (guiMajorType != MFMediaType_Video && guiMajorType != MFMediaType_Audio)
	{
		Throw(E_UNEXPECTED);
	}

	*ppMT = spMT.Detach();
}

HRESULT Helpers::CopySample(_In_ IMFSample *pSample, _Out_ IMFSample **ppSample)
{
	HRESULT hr = S_OK;

	// recreate IMFSample
	ComPtr<IMFSample> spSample;
	*ppSample = nullptr;
	hr = MFCreateSample(&spSample);

	if (SUCCEEDED(hr))
	{
		ComPtr<IMFMediaBuffer> myMediaBuffer;
		hr = pSample->ConvertToContiguousBuffer(&myMediaBuffer);

		/*DWORD cbLength;
		hr = pSample->GetTotalLength(&cbLength);

		if (SUCCEEDED(hr))
		MFCreateMemoryBuffer(cbLength, &myMediaBuffer);

		if (SUCCEEDED(hr))
		hr = pSample->CopyToBuffer(myMediaBuffer.Get());*/

		if (SUCCEEDED(hr))
			hr = spSample->AddBuffer(myMediaBuffer.Get());
	}

	if (SUCCEEDED(hr))
	{
		hr = pSample->CopyAllItems(spSample.Get());
	}

	if (SUCCEEDED(hr))
	{
		LONGLONG sampleTime;
		hr = pSample->GetSampleTime(&sampleTime);

		if (SUCCEEDED(hr))
		{
			hr = spSample->SetSampleTime(sampleTime);
		}
	}

	if (SUCCEEDED(hr))
	{
		LONGLONG sampleDuration;
		hr = pSample->GetSampleDuration(&sampleDuration);

		if (SUCCEEDED(hr))
		{
			hr = spSample->SetSampleDuration(sampleDuration);
		}
	}

	// Optimization: Currently no flags are defined on IMFSample
	/*if (SUCCEEDED(hr))
	{
	DWORD sampleFlags;
	hr = pSample->GetSampleFlags(&sampleFlags);

	if (SUCCEEDED(hr))
	{
	hr = spSample->SetSampleFlags(sampleFlags);
	}
	}*/

	*ppSample = spSample.Detach();
	return hr;
}